package controller;

import java.awt.event.*;

import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Node;
import javax.swing.event.MouseInputListener;
import javax.vecmath.Point3d;

import node.GeoNode;

import com.sun.j3d.utils.picking.PickCanvas;
import com.sun.j3d.utils.picking.PickIntersection;
import com.sun.j3d.utils.picking.PickResult;

import component.AbstractComponent;
import component.group.CanRemoveComponents;
import component.group.ComponentGroup;

abstract public class AbstractController implements MouseInputListener, MouseWheelListener, KeyListener {

	protected final Canvas3D canvas;
	protected final BranchGroup pickableBranch;
	
	protected final PickCanvas pickCanvas;
	
	public AbstractController(Canvas3D canvas, BranchGroup pickableBranch) {
		this.canvas = canvas;
		this.pickableBranch = pickableBranch;
		
		pickCanvas = new PickCanvas(canvas, pickableBranch);
	}
	
	abstract public void activate();
	abstract public void deactivate();
	
	protected boolean deleteSelection(ComponentGroup deleteSelection) {
		if (deleteSelection == null || deleteSelection.isEmpty()) {
			return false;
		}
		
		CanRemoveComponents canRemove = new CanRemoveComponents(deleteSelection);
		if (canRemove.canRemove()) {
			deleteSelection.disposeAll();
			deleteSelection.clear();
			return true;
		}
		return false;
	}
	
	protected boolean canDeselect() {
		return true;
	}

	protected PickResult pickClosest(MouseEvent e) {
		pickCanvas.setShapeLocation(e);
		Point3d camPos = pickCanvas.getStartPosition();
		PickResult results[] = pickCanvas.pickAll();
		if (results == null || results.length == 0) return null;
		int pos=-1;
		double distance = -1;
		double tmp;
		PickIntersection intersection;
		for (int i=0; i<results.length; i++) {
			intersection = results[i].getClosestIntersection(camPos);
			if (intersection == null) continue;
			tmp = camPos.distance(intersection.getPointCoordinatesVW());
			if (pos < 0 || tmp < distance) {
				pos = i;
				distance = tmp;
			}
		}
		if (pos < 0) return null;
		return results[pos];
	}
	
	protected AbstractComponent getComponent(PickResult result) {
		if (result == null) return null;
		Node node = result.getNode(PickResult.BRANCH_GROUP);
		if (node instanceof GeoNode) {
			return ((GeoNode)node).getComponent();
		}
		return null;
	}

}
